# Please install OpenAI SDK first: `pip3 install openai`

import os
import json
from datetime import datetime
from openai import OpenAI
from PIL import Image, ImageDraw, ImageFont
import logging
import re
import configparser
import weekyun

logging.basicConfig(level=logging.WARNING, format=' %(levelname)s - %(lineno)d 行- %(message)s')
logger = logging.getLogger(__name__)

# 基础数据
ELEMENT_SCORES = {'木': 0, '火': 0, '土': 0, '金': 0, '水': 0}
# Read config file
config = configparser.ConfigParser()
config.read('config.cfg',encoding='utf-8')

class DateCalculator:
    def __init__(self):
        # Load base data from file
        with open('base_data.txt', 'r', encoding='utf-8') as f:
            data = json.load(f)
            
        self.jqnames = data['JQNAMES']
        self.tg = data['TG']
        self.dz = data['DZ']
        self.jieling_names = data['JIELING_NAMES']
        self.tg_wx = data['TG_WX']
        self.dz_wx_yy = data['DZ_WX_YY']
        self.dz_wx_ss = data['DZ_WX_SS']
        
        # Load other data files
        with open('1800-2100jieqi.json','r',encoding='utf-8',errors='ignore') as f:
            self.dic=json.load(f)

    def gzodr(self,n,j): #校准超过10或12,或负数的天干地支序数
        if j=='g':
            if n>9:
                n=n-10
            if n<0:
                n=n+10
        elif j=='z':
            if n>11:
                n=n-12
            if n<0:
                n=n+12
        return n
    
    def cal_yd(self,n,o=1899): #先计算这年的元旦干支,已知1900年元旦是 甲戌日
        if n==1900:
            return [0,10]
        elif n>1900:            
            days=(datetime.strptime(str(n)+'-1-1','%Y-%m-%d')-datetime.strptime('1900-1-1','%Y-%m-%d')).days
            odr_tg=self.gzodr(days%10+0,'g')
            odr_dz=self.gzodr(days%12+10,'z')
            logger.debug(['距1900年元旦的天数：',days,'元旦的干支序数：',odr_tg,odr_dz])
            
            return [odr_tg,odr_dz]
        else:
            return [-1,-1]
    
    def inputdate(self,y,m,d,h=0,min=0,zishi=0):
        self.jqlist=self.dic[str(y)]
        
        ymdhm=str(y)+"-"+ str(m)+ '-' +str(d)+'-'+str(h)+'-'+str(min)

        self.jqdate=[]
        for i in self.jqnames:
            ptn=r'\d+年.+日'
            ptn_time=r'\d\d:\d\d:\d\d'
            ptn_lunar=r'农历.+'
            tmp_jq=re.search(ptn,self.jqlist[i])
            tmp_jq_time=re.search(ptn_time,self.jqlist[i])
            tmp_jq_lunar=re.search(ptn_lunar,self.jqlist[i])
            self.jqdate.append([i,tmp_jq[0],tmp_jq_time[0],tmp_jq_lunar[0]])
            
        logger.debug(self.jqdate) #当年的节气时间总表,数组形式
            
        for i in self.jqdate:
            i[1]=i[1].replace('年','-').replace('月','-')[0:-1]
            
        
        input_time=datetime.strptime(ymdhm, '%Y-%m-%d-%H-%M')
        self.jq_section=[]
        n=0

        for i in self.jqdate:
            list_time=datetime.strptime(i[1]+'-'+i[2][0:5], '%Y-%m-%d-%H:%M')
            if list_time>input_time:
                self.jq_section.append(n-1)
                self.jq_section.append(self.jqdate[n-1][0])
                self.jq_section.append(self.jqdate[n][0])
                break            
            n+=1
        
        # print(self.jq_section)
        if self.jq_section:
            pass
        else:
            self.jq_section.append(23)
            self.jq_section.append('冬至')
            self.jq_section.append('小寒')

            
        if (self.jq_section[0])%2==0:
            m_odr=self.jq_section[0]/2
        else:
            m_odr=(self.jq_section[0]-1)/2
            
        m_odr=m_odr if m_odr>0 else m_odr+12
            
            
        self.jq_section.append(m_odr)
        
        logger.debug(['输入的日期在今年的节气分段：',self.jq_section])  #[节气序数，节气，节气，月份的序号]

        return {'jq_section':self.jq_section}
    
    def cal_dateGZ(self,y,m,d,h=-1,min=0,zishi=0,real_sun_time='no',longtitude=120):
        txt_input_time=str(y)+'-'+str(m)+'-'+str(d)+' '+str(h).zfill(2)+':'+str(min).zfill(2)
        
        if real_sun_time=='yes':
            new_time=self.real_sun_time_transfer(y,m,d,h,min,long=longtitude)

            y=int(new_time['real_sun_time'].year)
            m=int(new_time['real_sun_time'].month)
            d=int(new_time['real_sun_time'].day)
            h=int(new_time['real_sun_time'].hour)
            min=int(new_time['real_sun_time'].minute)
            

            res_real_sun_time=new_time['real_sun_time'].strftime('%Y-%m-%d %H:%M')
            res_ping_sun_time=new_time['ping_sun_time'].strftime('%Y-%m-%d %H:%M')
        else:
            res_real_sun_time='real sun time not calculate'
            res_ping_sun_time='ping sun time not calculate'
        
        
        # 因为23-0点涉及日期变动，先按输入参数校正
        # zishi==0, 23-0点按下一天的子时处理，默认
        # zishi==1, 23-0点按当天的子时处理
        _date=str(y)+'-'+str(m)+'-'+str(d)
        if h==23 and zishi==0:
            date_correct=datetime.strptime(_date,'%Y-%m-%d')+timedelta(days=1)     
            y=int(date_correct.strftime('%Y'))
            m=int(date_correct.strftime('%m'))
            d=int(date_correct.strftime('%d'))     
            
        dateGZ=self.inputdate(y,m,d,h,min)['jq_section']
        
        # logger.info(['按子时校正后的日期：',y,m,d])
        
        #年干支
        odr_yg=int(str(y-3)[-1])-1
        odr_yz=int((y-3)%12)-1

        #月干支
        if dateGZ[3]==0:
            realMon=12
        else:
            realMon=dateGZ[3]
        
        odr_mg=int(self.gzodr((odr_yg+1)*2+realMon,'g'))%10-1
        odr_mz=int(self.gzodr(dateGZ[3]+1,'z'))  #1月是丑月，列表从子开始，故+1
        
        logger.debug(['月序数：',odr_mg,odr_mz,'未按节气校正后的年干支序数：', \
                      odr_yg,odr_yz,dateGZ[3],realMon,(odr_yg+1)*2+realMon])
        
        if m==1 and dateGZ[3]>10  or m==2 and dateGZ[3]==12: #寅月前，算上一年
            odr_yg=int(str(y-1-3)[-1])-1
            odr_yz=odr_yz-1
            odr_mg=int(self.gzodr((odr_yg+1)*2+realMon,'g'))%10-1

        #日干支
        this_yd=self.cal_yd(y)
        if this_yd[0]!=-1: #如果年份<1900，将返回-1
            days_diff=(datetime.strptime(str(y)+'-'+str(m)+'-'+str(d),'%Y-%m-%d')- \
                                            datetime.strptime(str(y)+'-1-1','%Y-%m-%d')).days
            odr_dg=(this_yd[0]+days_diff)%10
            odr_dz=(this_yd[1]+days_diff)%12
            
        else:
            pass       
        
        #时干支        
        if h!=-1:
            if h==23:
                h=0
                
            if h%2==0:  #按十二个时辰来计算
                H=h/2
            else:
                H=(h+1)/2    
                
            if odr_dg==0 or odr_dg==5:
                odr_hg_0=0
            elif odr_dg==1 or odr_dg==6:
                odr_hg_0=2
            elif odr_dg==2 or odr_dg==7:
                odr_hg_0=4
            elif odr_dg==3 or odr_dg==8:
                odr_hg_0=6
            elif odr_dg==4 or odr_dg==9:
                odr_hg_0=8

            odr_hg=int(odr_hg_0+H)
            odr_hz=int(H)
        
            res=[self.tg[self.gzodr(odr_yg,'g')], \
                    self.dz[self.gzodr(odr_yz,'z')], \
                    self.tg[self.gzodr(odr_mg,'g')], \
                    self.dz[self.gzodr(odr_mz,'z')], \
                    self.tg[self.gzodr(odr_dg,'g')], \
                    self.dz[self.gzodr(odr_dz,'z')], \
                    self.tg[self.gzodr(odr_hg,'g')], \
                    self.dz[self.gzodr(odr_hz,'z')] 
                ]
        else:
            res=[self.tg[self.gzodr(odr_yg,'g')], \
                    self.dz[self.gzodr(odr_yz,'z')], \
                    self.tg[self.gzodr(odr_mg,'g')], \
                    self.dz[self.gzodr(odr_mz,'z')], \
                    self.tg[self.gzodr(odr_dg,'g')], \
                    self.dz[self.gzodr(odr_dz,'z')], \
                    '', \
                    ''] 

        return {'bazi':res,'input_time':txt_input_time,'real_sun_time':res_real_sun_time,'ping_sun_time':res_ping_sun_time}

class ImageGenerator:
    def __init__(self):
        # Read config file
        config = configparser.ConfigParser()
        config.read('config.cfg',encoding='utf-8')
        
        self.template_dir = config['Directories']['template_dir']
        self.output_base_dir = config['Directories']['output_base_dir']
        self.font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
        self.font_size = 30
        self.text_color = (0, 0, 0)  # 黑色
        self.text_position = (50, 800)  # 文本位置
        
        # 检查模板目录是否存在
        if not os.path.exists(self.template_dir):
            raise FileNotFoundError(f"模板目录不存在: {self.template_dir}")
            
        # 创建输出目录
        os.makedirs(self.output_base_dir, exist_ok=True)

    def generate_images(self, date_str, fortune_text):
        """生成五行运势图片"""
        date_dir = os.path.join(self.output_base_dir, date_str)
        os.makedirs(date_dir, exist_ok=True)
        
        # 解析运势文本
        element_texts = self._parse_fortune_text(fortune_text)
        
        # 生成每张图片
        image_paths = {}
        for element in ['木', '火', '土', '金', '水']:
            template_path = os.path.join(self.template_dir, f"{element}.jpg")
            if not os.path.exists(template_path):
                continue
                
            # 打开模板图片
            img = Image.open(template_path)
            draw = ImageDraw.Draw(img)
            
            # 添加文本
            font = ImageFont.truetype(self.font_path, self.font_size)
            text = element_texts.get(element, "")
            draw.text(self.text_position, text, font=font, fill=self.text_color)
            
            # 保存图片
            output_path = os.path.join(date_dir, f"{element}.jpg")
            img.save(output_path)
            image_paths[element] = output_path
            
        return image_paths

    def _parse_fortune_text(self, text):
        """解析运势文本，提取每种五行的建议"""
        element_texts = {}
        lines = text.split('\n')
        
        current_element = None
        for line in lines:
            if '宝宝' in line:
                # 提取五行元素
                current_element = line.split('宝宝')[0][-1]
                element_texts[current_element] = line + '\n'
            elif current_element:
                element_texts[current_element] += line + '\n'
                
        return element_texts


class FortuneGenerator:
    def __init__(self):
        self.client = OpenAI(
            api_key="sk-be54134844dc4f29a7bccbc3fc0ea8bd",
            base_url="https://api.deepseek.com"
        )

        # Read config file
        config = configparser.ConfigParser()
        config.read('config.cfg',encoding='utf-8')
        
        self.fortune_txt_lib_path = config['Directories']['fortune_txt_lib_path']
        
        self.date_calculator = DateCalculator()
        
        # Load base data from file
        with open('base_data.txt', 'r', encoding='utf-8') as f:
            data = json.load(f)
            
        self.ELEMENTS = data['ELEMENTS']
        self.TIAN_GAN = data['TIAN_GAN']
        self.DI_ZHI = data['DI_ZHI']
        self.SAN_HE = data['SAN_HE']
        self.SAN_HUI = data['SAN_HUI']
        self.SHI_SHEN = data['SHI_SHEN']
        self.SUMMARY_KEYWORDS = data['SUMMARY_KEYWORDS']
        
        # 五行图标映射
        self.element_icons = {
            '木': '🌳',
            '火': '🔥',
            '土': '⛰️',
            '金': '⚔️',
            '水': '💧'
        }
        
        # Load fortune data
        self._load_fortune_data()
        self._load_config()
        
        self.lucky_color_dir = config['Directories']['lucky_color_dir']
        self.template_dir = config['Directories']['template_dir']
        self.output_base_dir = config['Directories']['output_base_dir']
        os.makedirs(self.output_base_dir, exist_ok=True)

    def _load_fortune_data(self):
        with open(self.fortune_txt_lib_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
            
        self.GE_JU = data['GE_JU']
        self.COLOR_MAP = data['COLOR_MAP']
        self.FORTUNE_KEYWORDS = data['FORTUNE_KEYWORDS']
        
        # Convert string conditions to executable functions
        for key, value in self.GE_JU.items():
            if 'condition' in value and isinstance(value['condition'], str):
                self.GE_JU[key]['condition'] = eval(value['condition'])

    def _load_config(self):
        """加载配置文件"""
        with open('reference_text.txt', 'r', encoding='utf-8') as f:
            self.reference_text = f.read()

        with open('system_role.txt', 'r', encoding='utf-8') as f:
            self.system_role = f.read()

        with open('prompt.txt', 'r', encoding='utf-8') as f:
            self.prompt_template = f.read()
    
    def _get_daily_fortune_by_date(self, date_str,geju_txt_dir):
        """根据日期获取每日运势"""
        from ganzhi import DayFortune
        df = DayFortune(geju_txt_dir=geju_txt_dir)
        return df.get_daily_fortune_by_date(date_str)

    def generate_fortune(self, date_str,geju_txt_dir):
        df=self._get_daily_fortune_by_date(date_str,geju_txt_dir)
        wx_page_prompt={}
        tg_notice=', '.join(word for sublist in df['date_rels']['天干关系'] for word in sublist)
        dz_notice=', '.join(word for sublist in df['date_rels']['地支关系'] for word in sublist)
        # 只有当两者都不为空时才用 " | " 连接，否则取不为空的项
        notice = ' | '.join(filter(None, [tg_notice, dz_notice]))
                            
        date_info={
            'date':datetime.strftime(datetime.strptime(date_str,'%Y%m%d%H%M'),'%Y-%m-%d'),
            'date_liuzi':df['date_gz']
        }
        for wx in ELEMENT_SCORES.keys():
            wx_page_prompt[wx] = [df['date_rels']['五行最高权重简化十神'].get(wx,'')+'旺'] + df['date_rels']['五行十神格局'].get(wx,[])


            
        return {
            'date_info':date_info,
            'tg_dz_notices':notice,
            'wx_page_prompt': wx_page_prompt
        }

    def generate_fortune_ai(self,wx,color,luck,pre_text,prompt_input):
        if wx=='':
            wx='木'
        if color=='':
            color='红色，绿色'
        if luck=='':
            luck='【平】'
        if prompt_input=='':
            prompt_input='用能力扛住压力，工作压力虽大，但还是能掌控局面，特别想赚钱，多与粉丝互动, 有同事帮忙'

        # 生成每个五行的运势
        final_text = "" 

        # 静态部分
        static_text = f"{self.element_icons[wx]}  {wx}宝宝\n"
        static_text += f" 幸运色: {color}\n"
        # pre_text = f"{pre_text}\n"
        # static_text += f"{luck}\n"
        
        

        # 生成prompt
        prompt = f"{self.system_role}\n\n{wx}宝宝，{prompt_input}。以上内容，不应该简单地出现在最后生成的文本中，可以适当扩写，要流畅、沉稳的现代文风。这个是一天的运势，不要出现“一段时间”，“这段时间”这样表示时间段的词。用“{wx}宝宝”作主语，或用”你“作为主语，不要出现”他“或”她“他为主语。只写一段，不要再分段，也不要在文中出现冒号。50个字左右。"
        
        print(wx,':',prompt)
        # # 调用API获取动态内容
        response = self.client.chat.completions.create(
            model="deepseek-chat",
            messages=[
                {"role": "user", "content": prompt},
            ],
            temperature=1.4,
            stream=False
        )
        dynamic_text = response.choices[0].message.content
        dynamic_text = re.sub(r'\*\*|#|-', '', dynamic_text)
        
        # 合并静态和动态内容
        final_text += static_text
        final_text += f"{luck} {dynamic_text}\n"

        ############### 以下为测试用，正式时注释掉。
        # test_txt={
        #         "土": "⛰️  土宝宝\n 幸运色: 黄，黑\n 运势: 【平】 土宝宝今日运势平稳，适合与长辈或领导多交流，汲取经验智慧，保持低调姿态，静待时机，无需过度操劳，适时放松身心。\n",
        #         "木": "🌳  木宝宝\n 幸运色: 红，绿\n 运势: 【平】 木宝宝今天运势颇佳，与粉丝互动频繁，人气高涨，且得同事鼎力相助，工作顺遂，心情愉悦，整体状态积极向上。\n",
        #         "水": "💧  水宝宝\n 幸运色: 红，绿\n 运势: 【平】 水宝宝今日运势稳中有升，虽面临工作压力，但凭借自身能力与智慧，能够从容应对并掌控全局。善用人脉资源，或有意外的收获与突破，财运亦有望提升。\n",
        #         "火": "🔥  火宝宝\n 幸运色: 蓝\n 运势: 【平】 火宝宝今日运势稳中有升，适宜多与长辈或领导交流，汲取经验，把握机会，虽有躺平之念，但适度努力更显明智，保持平和心态，方能事半功倍。\n",
        #         "金": "⚔️  金宝宝\n 幸运色: 白，粉\n 运势: 【平】 金宝宝今日财运旺盛，宜多与长辈或领导沟通，贵人相助，机遇颇多，把握时机，稳步前行，收获可期。\n"
        #     }
        # test_txt_ai_txt={
        #         "土": "土宝宝今日运势平稳，适合与长辈或领导多交流，汲取经验智慧，保持低调姿态，静待时机，无需过度操劳，适时放松身心。\n",
        #         "木": "木宝宝今天运势颇佳，与粉丝互动频繁，人气高涨，且得同事鼎力相助，工作顺遂，心情愉悦，整体状态积极向上。\n",
        #         "水": "水宝宝今日运势稳中有升，虽面临工作压力，但凭借自身能力与智慧，能够从容应对并掌控全局。善用人脉资源，或有意外的收获与突破，财运亦有望提升。\n",
        #         "火": "火宝宝今日运势稳中有升，适宜多与长辈或领导交流，汲取经验，把握机会，虽有躺平之念，但适度努力更显明智，保持平和心态，方能事半功倍。\n",
        #         "金": "金宝宝今日财运旺盛，宜多与长辈或领导沟通，贵人相助，机遇颇多，把握时机，稳步前行，收获可期。\n"
        #     }
        
        # final_text=test_txt[wx]    
        # dynamic_text=test_txt_ai_txt[wx]            
        ###############

        print('text:\n',final_text)

        return {'final_text':final_text,'wx':wx,'luck':luck,'color':color,'pre_text':pre_text,'ai_text':dynamic_text}

        # # 生成图片
        # date_str = date_obj.strftime('%Y%m%d')
        # image_paths = ImageGenerator().generate_images(date_str, final_text)
        
        # # 转换路径为web可访问路径
        # web_paths = {}
        # for element, path in image_paths.items():
        #     web_paths[element] = f'/temp_images/{date_str}/{os.path.basename(path)}'

class GenerateWeekYun():
    def __init__(self):
        pass

    def run_week_txt_cover(self,fn_num=1,prd=['20220822','20220828'],sense_word_judge='yes',desc_txt_show='yes',file_types='img_txt'):
        work_dir=config['Directories']['ganzhi_work_dir']
        output_dir=config['Directories']['output_dir']
        if fn_num=='1':
            xls=os.path.join(work_dir,'运势','运势.xlsx')
        else:
            xls=os.path.join(work_dir,'运势','运势2.xlsx')

        try:

            eachday_output_dir=os.path.join(output_dir,'日穿搭')
            cover_save_dir=os.path.join(output_dir,'日穿搭','0-每周运势封图')

            print('\n正在处理每日穿搭配色图\n')
            week_pic=weekyun.ExportImage(work_dir=work_dir)            
            dec_txt=week_pic.batch_deal(prd=prd,out_put_dir=eachday_output_dir,xls=xls)        
             
       
            if dec_txt['res']=='ok':
                # print('\n正在处理每日穿搭配色图\n')
                # week_pic=week_yun.ExportImage(work_dir=work_dir)

                print('\n正在处理每日穿搭配色文案..\n')
                week_txts=weekyun.ExportWeekYunTxt(work_dir=work_dir,import_dec_dic=dec_txt)
                
                all_txt=week_txts.all_date_wx(prd=prd,xls=xls,save='yes',save_dir=eachday_output_dir,sense_word_judge=sense_word_judge,desc_txt_show=desc_txt_show)
                

                if file_types=='img_txt_video':
                    print('\n正在生成视频\n')
                    videos=weekyun.videoClips(work_dir=work_dir,import_dec_dic=dec_txt,import_txt=all_txt)
                    videos.batch_export_video(prd=prd,xls=xls,save='no',save_dir=eachday_output_dir,sense_word_judge='no')


                return {'res':'ok'}
            else:
                return {'res':'failed','error':dec_txt['error']}
        except Exception as e:
            # raise FERROR('error where generate riyun pics and txt')
            print(e)
            return {'res':'failed','error':'error when generate riyun pics and txt：'+str(e)}  
    
    


if __name__ == '__main__':
    # 测试代码
    generator = FortuneGenerator()
    # generator.generate_fortune_ai('','','')
    fortune=generator.generate_fortune('202502100808',geju_txt_dir='D:\\jacklocal工作目录2\\ejj\\素材\\config')
    print(fortune)
